package ch.ethz.fcl.metrofont;

import java.awt.image.BufferedImage;
import java.util.ArrayList;

import static org.lwjgl.opengl.GL11.*;

public class TextureGlyph {
	private char charcode;
	private int width, height;
	private int offset_x, descender;
	private int texCoorX, texCoorY;
	private int advance_x;

	ArrayList<KerningPair> kernings = null;
	private BufferedImage image;

	public TextureGlyph(char code) {
		this.charcode = code;
		kernings = new ArrayList<KerningPair>();
	}

	public TextureGlyph(char code, int width, int height, int offset_x,
			int descender) {
		this.charcode = code;
		this.width = width;
		this.height = height;
		this.offset_x = offset_x;
		this.descender = descender;
		kernings = new ArrayList<KerningPair>();
	}

	// get the character of this glyph
	public char getCode() {
		return charcode;
	}

	public BufferedImage getImage() {
		return image;
	}

	// set the coords of the char in the atlas
	public void setTexCoord(int x, int y) {
		texCoorX = x;
		texCoorY = y;
	}

	public void setAddvanceX(int advance_x) {
		this.advance_x = advance_x;
	}

	public int getAddvanceX() {
		return this.advance_x;
	}

	public void addKerning(KerningPair kerning) {
		this.kernings.add(kerning);
	}

	public void setDescender(int descender) {
		this.descender = descender;
	}

	public int getDescender() {
		return this.descender;
	}

	public void setOffsetX(int offset_x) {
		this.offset_x = offset_x;
	}

	public int getOffsetX() {
		return this.offset_x;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getWidth() {
		return width;
	}

	public void buildImage(BufferedImage image) {
		this.image = image;
	}

	public void render(TextureFont fr, TextureAtlas atlas, char previous_code,
			Pen pen, boolean display) {
		float scale = pen.getFontSize() / fr.getMarkup().getFontSize();
		if (previous_code != (char) 0) {
			float kerning = getKerning(previous_code);
			pen.setX(pen.getX() + kerning * (float) Math.cos(pen.getXYAngle())
					* scale);
			pen.setY(pen.getY() + kerning * (float) Math.sin(pen.getXYAngle())
					* scale);
		}

		float u0 = (this.texCoorX) / (float) atlas.getWidth();
		float u1 = (this.texCoorX + this.width) / (float) atlas.getWidth();
		// y coordinate is opp
		float v1 = (this.texCoorY) / (float) atlas.getHeight();
		float v0 = (this.height + this.texCoorY) / (float) atlas.getHeight();

		float x0 = pen.getX() + offset_x * scale;
		float y0 = pen.getY() - descender * scale;
		float x1 = x0 + this.width * scale;
		float y1 = y0 + this.height * scale;

		Point2D p0 = new Point2D(pen.getX(), pen.getY()).rotate(new Point2D(x0,
				y0), pen.getXYAngle());
		Point2D p1 = new Point2D(pen.getX(), pen.getY()).rotate(new Point2D(x0,
				y1), pen.getXYAngle());
		Point2D p2 = new Point2D(pen.getX(), pen.getY()).rotate(new Point2D(x1,
				y1), pen.getXYAngle());
		Point2D p3 = new Point2D(pen.getX(), pen.getY()).rotate(new Point2D(x1,
				y0), pen.getXYAngle());

		if (display) {
			glBegin(GL_TRIANGLES);
			{
				glTexCoord2f(u0, v0);
				glVertex2f(p0.getX(), p0.getY());
				glTexCoord2f(u0, v1);
				glVertex2f(p1.getX(), p1.getY());
				glTexCoord2f(u1, v1);
				glVertex2f(p2.getX(), p2.getY());

				glTexCoord2f(u0, v0);
				glVertex2f(p0.getX(), p0.getY());
				glTexCoord2f(u1, v1);
				glVertex2f(p2.getX(), p2.getY());
				glTexCoord2f(u1, v0);
				glVertex2f(p3.getX(), p3.getY());
			}
			glEnd();
		}

		pen.setX(pen.getX() + (this.advance_x + fr.getMarkup().getSpacing())
				* (float) Math.cos(pen.getXYAngle()) * scale);
		pen.setY(pen.getY() + (this.advance_x + fr.getMarkup().getSpacing())
				* (float) Math.sin(pen.getXYAngle()) * scale);
	}

	public int getKerning(char code) {
		if (this.kernings == null)
			return 0;

		for (int i = 0; i < this.kernings.size(); i++)
			if (kernings.get(i).getCode() == code)
				return kernings.get(i).getKerning();

		return 0;
	}
}
